package per.ethan.ssm.exception;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpStatus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import per.ethan.ssm.domain.ErrorCodeVO;
import per.ethan.ssm.domain.ResultBean;

import javax.xml.bind.ValidationException;
import java.util.StringJoiner;

/**
 * @author Ethan
 * @date 2020/03/29 11:30
 * 全局异常处理
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 自定义异常
     *
     * @param e 异常
     * @return 错误信息
     */
    @ExceptionHandler(value = ServiceException.class)
    public ResultBean<ErrorCodeVO> handlerServiceException(ServiceException e) {
        log.error(e.getMessage(), e);
        return ResultBean.error(e.getErrorCodeVO());
    }

    /**
     * 参数绑定异常
     *
     * @param e 异常
     * @return 错误信息
     */
    @ExceptionHandler(value = BindException.class)
    public ResultBean<ErrorCodeVO> handlerBindException(BindException e) {
        log.error(e.getMessage(), e);
        StringJoiner joiner = new StringJoiner(";");
        e.getBindingResult().getFieldErrors().forEach(error -> joiner.add(error.getDefaultMessage()));
        return ResultBean.error(new ErrorCodeVO(HttpStatus.HTTP_INTERNAL_ERROR, joiner.toString()));
    }

    /**
     * 字段校验异常
     *
     * @param e 异常
     * @return 错误信息
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ResultBean<ErrorCodeVO> handlerMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        log.error(e.getMessage(), e);
        StringJoiner joiner = new StringJoiner(";");
        e.getBindingResult().getFieldErrors().forEach(error -> joiner.add(error.getDefaultMessage()));
        return ResultBean.error(new ErrorCodeVO(HttpStatus.HTTP_INTERNAL_ERROR, joiner.toString()));
    }

    /**
     * 参数校验异常
     *
     * @param e 异常
     * @return 错误信息
     */
    @ExceptionHandler(value = ValidationException.class)
    public ResultBean<ErrorCodeVO> handlerValidationException(ValidationException e) {
        log.error(e.getMessage(), e);
        return ResultBean.error(new ErrorCodeVO(HttpStatus.HTTP_INTERNAL_ERROR, e.getMessage()));
    }

    /**
     * controller参数异常
     *
     * @param e 异常
     * @return 错误信息
     */
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    public ResultBean<ErrorCodeVO> handlerMissingServletRequestParameterException(MissingServletRequestParameterException e) {
        log.error(e.getMessage(), e);
        return ResultBean.error(new ErrorCodeVO(HttpStatus.HTTP_INTERNAL_ERROR, e.getMessage()));
    }

    /**
     * 处理方法不支持异常
     *
     * @param e 异常
     * @return 错误信息
     */
    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    public ResultBean<ErrorCodeVO> handlerHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        log.error(e.getMessage(), e);
        return ResultBean.error(new ErrorCodeVO(HttpStatus.HTTP_BAD_METHOD, e.getMessage()));
    }

    /**
     * 其它未知异常
     *
     * @param e 异常
     * @return 错误信息
     */
    @ExceptionHandler(value = Exception.class)
    public ResultBean<ErrorCodeVO> handlerException(Exception e) {
        log.error(e.getMessage(), e);
        return ResultBean.error(
                new ErrorCodeVO(500,
                        StrUtil.isEmpty(e.getMessage()) ?
                                ExceptionUtil.stacktraceToOneLineString(e, 100) : e.getMessage())
        );
    }

}
